package com.jyx.auth.service;

import com.alibaba.fastjson.JSON;
import com.jyx.auth.dao.JyxUserRepository;
import com.jyx.framework.domain.ucenter.JyxUser;
import com.jyx.framework.domain.ucenter.request.RegisterRequest;
import com.jyx.framework.model.response.CommonCode;
import com.jyx.framework.model.response.ResponseResult;
import com.jyx.framework.utils.CookieUtil;
import com.sun.jersey.core.util.Base64;
import com.jyx.framework.clinet.JyxServiceList;
import com.jyx.framework.domain.ucenter.ext.AuthToken;
import com.jyx.framework.domain.ucenter.response.AuthCode;
import com.jyx.framework.exception.ExceptionCast;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class AuthService {
    private static final Logger LOGGER = LoggerFactory.getLogger(AuthService.class);

    @Value("${auth.tokenValiditySeconds}")
    int tokenValiditySeconds;
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    LoadBalancerClient loadBalancerClient;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    JyxUserRepository jyxUserRepository;


    public AuthToken login(String username,String password,String cliendId,String clientSecret){
        //申请校验码
        AuthToken authToken = applyToken(username, password, cliendId, clientSecret);
        if(authToken == null){
            ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);
        }
        //将token转成json存储到redis
        String access_token = authToken.getAccess_token();
        //Map<String, String> jsonMap = new HashMap<>();
        //String access_token2 = jsonMap.put("access_token", access_token);
        //String jsonToken = JSON.toJSONString(access_token);
        //boolean saveResult = saveToken(access_token, jsonToken, tokenValiditySeconds);
        boolean saveResult = saveToken(access_token, access_token, tokenValiditySeconds);
        if(!saveResult){
            ExceptionCast.cast(AuthCode.AUTH_LOGIN_TOKEN_SAVEFAIL);
        }
        return authToken;
    }

    /**
     * 保存token
     * @param access_token
     * @param jsonToken
     * @param tokenValiditySeconds
     * @return
     */
    private boolean saveToken(String access_token, String jsonToken, long tokenValiditySeconds) {
        String name = "user_token:"+access_token;
        stringRedisTemplate.boundValueOps(name).set(jsonToken,tokenValiditySeconds, TimeUnit.SECONDS);
        Long expire = stringRedisTemplate.getExpire(name);
        return expire>0;
    }

    /**
     * 申请令牌
     * @param username
     * @param password
     * @param cliendId
     * @param clientSecret
     * @return
     */
    private AuthToken applyToken(String username, String password, String cliendId, String clientSecret) {
        ServiceInstance serviceInstance = loadBalancerClient.choose(JyxServiceList.JYX_SERVICE_UCENTER_AUTH);
        if(serviceInstance == null){
            LOGGER.error("Choose a service instance failed.");
            ExceptionCast.cast(AuthCode.AUTH_LOGIN_AUTHSERVICE_NOTFOUND);
        }
        URI uri = serviceInstance.getUri();
        String authUrl = uri + "/auth/oauth/token";
        //编写请求信息
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("grant_type", "password");
        formData.add("username",username);
        formData.add("password",password);
        //请求头
        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
        headers.add("Authorization",httpBasic(cliendId,clientSecret));
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){
            @Override
            public void handleError(ClientHttpResponse response) throws IOException {
                if(response.getRawStatusCode()!=400 && response.getRawStatusCode()!=401) {
                    super.handleError(response);
                }
            }
        });
        Map map = null;
        try {
            ResponseEntity<Map> exchange = restTemplate.exchange(authUrl, HttpMethod.POST,
                    new HttpEntity<MultiValueMap<String, String>>(formData, headers), Map.class);
            map = exchange.getBody();
        }catch (RestClientException e){
            LOGGER.error("Request oauth_token_password error:{}",e.getMessage());
            e.printStackTrace();
            ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL);
        }
        if(map == null || map.get("access_token")==null || map.get("refresh_token")==null || map.get("jti")==null){

            ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_ISNULL);
        }
        AuthToken authToken = new AuthToken();
        String access_token = (String) map.get("access_token");
        String refresh_token = (String) map.get("refresh_token");
        String jwt_token = (String) map.get("jti");
        authToken.setJwt_token(jwt_token);
        authToken.setAccess_token(access_token);
        authToken.setRefresh_token(refresh_token);
        return authToken;
    }

    //获取httpbasic认证串
    private String httpBasic(String cliendId, String clientSecret) {
        String clientString = cliendId + ":" + clientSecret;
        byte[] encode = Base64.encode(clientString.getBytes());
        return "Basic " + new String(encode);

    }

    /**
     * 根据授权token查询用户授权码
     * @param access_token
     * @return
     */
    public AuthToken getUserToken(String access_token) {
        String userToken = "user_token:" + access_token;
        String userTokenString = stringRedisTemplate.opsForValue().get(userToken);
        if(userTokenString!=null){
            AuthToken authToken = new AuthToken();
            try {
                authToken.setJwt_token(userTokenString);
                //Object parse = JSON.parse(userTokenString);
                //JSON.parseObject(parse, AuthToken.class);
                //authToken = JSON.parseObject(userTokenString, AuthToken.class);
            }catch (Exception e){
                LOGGER.error("parse AuthToken error:{}",e.getMessage());
                e.printStackTrace();
            }
            return authToken;
        }


        return null;
    }

    public boolean delToken(String uid) {
        if (StringUtils.isEmpty(uid)) {
            LOGGER.info("当前uid已为空，无需删除~");
            return true;
        }
        String name = "user_token:" + uid;
        stringRedisTemplate.delete(name);
        return true;
    }

    /**
     * 在cookie获取token
     * @param request
     * @return
     */
    public String getTokenFromCookie (HttpServletRequest request){
        Map<String, String> cookieMap = CookieUtil.readCookie(request, "uid");
        String access_token = cookieMap.get("uid");
        if (StringUtils.isEmpty(access_token)) {
            return null;
        }
        return access_token;
    }

    /**
     * 在请求头获取jwt
     * @param request
     * @return
     */
    public String getJwtFromHeader(HttpServletRequest request){
        String authorization = request.getHeader("Authorization");
        if (StringUtils.isEmpty(authorization)) {
            return null;
        }
        if(!authorization.startsWith("Bearer ")){
            return null;
        }

        return authorization;
    }

    /**
     * 获取token的有效时间
     * @param access_token
     * @return
     */
    public Long getExpire(String access_token){
        String key = "user_token:" + access_token;
        Long expire = stringRedisTemplate.getExpire(key);
        return expire;
    }

    public ResponseResult register(RegisterRequest registerRequest) {
        if(registerRequest == null || StringUtils.isEmpty(registerRequest.getUsername())){
            return new ResponseResult(CommonCode.FAIL);
        }
        JyxUser jyxUser = new JyxUser();
        jyxUser.setUsername(registerRequest.getUsername());
        jyxUser.setUtype("17");
        jyxUser.setPhone(registerRequest.getPhone());
        String oldPass = registerRequest.getPassword();
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String dbPass = passwordEncoder.encode(oldPass);
        jyxUser.setPassword(dbPass);
        jyxUserRepository.save(jyxUser);
        return new ResponseResult(CommonCode.SUCCESS);
    }
}
